-
Couldn't load subscription status.
- Fork 1
[Command] Addition of a simple command make_variant
#35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
02f7a23 to
40fe15e
Compare
40fe15e to
b93b2f5
Compare
|
|
||
| with tempfile.TemporaryDirectory() as _tmpdir: | ||
| tempdir = pathlib.Path(_tmpdir) | ||
| wheel_unpack(input_filepath, tempdir) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we really need to unpack it. Unfortunately, it looks like zipfile lacks proper API to update files in place or copy compressed members (python/cpython#125718), but at least we could avoid writing files to disk and potentially altering their metadata in the process.
I.e. basically open both archives, iterate over members: if not metadata, copy between archives as-is; if metadata, read, alter and write. It will probably even be simpler than the current logic, which seems to make unnecessary changes to the archive (probably because it was adapted from the command altering tags, which we don't do here).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't disagree though it's a little complicated for a first iteration - feel free to experiment and optimize ;)
Co-authored-by: Michał Górny <[email protected]>
Co-authored-by: Michał Górny <[email protected]>
Co-authored-by: Michał Górny <[email protected]>
Co-authored-by: Michał Górny <[email protected]>
|
Good enough for a V1 of the command - merging so that a few people can start playing with it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for writing this! I think this may end up being a very common way to create variant wheels.
Comments given; I hope I'm not being too nitpicky!
|
|
||
| # Input Validation | ||
| variant_hash_pattern = rf"^[a-fA-F0-9]{{{VARIANT_HASH_LEN}}}$" | ||
| if not re.match(variant_hash_pattern, variant_hash): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If wheel_variant_pack() is an internal API, then you control the variant_hash and this could probably be an assertion.
| raise whl_pck.WheelError( | ||
| f"Multiple .dist-info directories found in {directory}" | ||
| ) | ||
| if not dist_info_dirs: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you're checking the length of a list, and you're explicitly calling len() above, it's probably best to also do so here, e.g. if len(dist_info_dirs) == 0:
| tags: list[str] = info.get_all("Tag", []) | ||
| existing_build_number = info.get("Build") | ||
|
|
||
| if not tags: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another place where it's generally better to use if len(tags) == 0:
I generally prefer to be as explicit about the truthiness test as possible. E.g. if you know you're testing the length of a sequence, use len. If you are testing whether something is None or not, use if foo is None. Only when the truthiness or falseiness can be any number of things (e.g. None, the empty string, or a zero length sequence) do I typically use a generic if foo or if not foo. YMMV!
| if not tags: | ||
| raise whl_pck.WheelError( | ||
| f"No tags present in {dist_info_dir}/WHEEL; cannot determine target " | ||
| f"wheel filename" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm kind of surprised you didn't get a linter warning here, since the line 78 string doesn't need to be an f-string.
| del info["Build"] | ||
| if build_number: | ||
| info["Build"] = build_number | ||
| name_version += "-" + build_number |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one could be an f-string: name_version += f"-{build_number}"
| ] | ||
|
|
||
| [project.optional-dependencies] | ||
| user = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about using cli (or commands) for the optional instead?
| Minimal changes tried to be applied to make it work with the Variant Hash. | ||
| :param directory: The unpacked wheel directory | ||
| :param dest_dir: Destination directory (defaults to the current directory) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it? Or is it required?
| if not (metadata_f := distinfo_dir / "METADATA").exists(): | ||
| raise FileNotFoundError(metadata_f) | ||
|
|
||
| with metadata_f.open(mode="r+") as file: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think it would be better to write a new file and move it into place atomically? E.g. copy lines from METADATA into METADATA.new, then os.rename() the latter to the former. The question I have is, what if this loop errors out or is interrupted in the middle of it? You can probably also avoid the seek() back to the beginning and the truncate().
You probably still need a try/except that deletes the .new file and cleans up after itself, reraising the original exception, but at least then you can still recover back to the original state if something unexpected happens.
| METADATA_VARIANT_HASH_HEADER = "Variant-hash" | ||
| METADATA_VARIANT_PROPERTY_HEADER = "Variant" | ||
|
|
||
| WHEEL_NAME_VALIDATION_REGEX = re.compile( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A multi-line regex string with comments would help with readability here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, I agree here but the regex is copied (and slightly modified) from pip (and we already have it repeated in too many places).
|
Thanks a lot @warsawnv for your comments. Many of the comments you made are actually directly targeting the original implementation from wheel.cli.pack. I'm gonna check tomorrow what is the original code (which I don't want to modify) and which one my code (and I can improve). I believe in the future some of that code may go inside wheel itself. Let's see. In any case thanks for the comments, I'll check what I can improve and I'll open a new PR with these changes. |
* [Command] `generate-index-json` updated. According to #35 * Review Fixes
This PR adds a command
variantlib make_variantto manually add variant information "post build" to a wheel.You can see it as "repackaging a wheel as a variant after a build".
This will be very useful to allow everybody to quickly transform any wheel into a variant without having to modify absolutely anything else.
variantlib make_variant \ -f pep_xxx_wheel_variants-1.0.0-py3-none-any.whl \ -o . -p fictional_tech::quantum::drive \ -p fictional_hw::platform::TARSAfter discussing with @warsawnv we thought that this was a critical feature to support initially (as build backends gradually rollout support) and for testing.
This PR also include a "optional extra" called
user- Just because this command adds a feature onwheelwhich will not be useful in most cases (like forpipand I'm not sure how ifpipand other would like very much having to bringwheel), we can change that part later if we think it's not a big deal to addwheelas a core dependency.This PR uses #33